//
// FILE NAME: CIDLib_DevMacros.hpp
//
// AUTHOR: Dean Roddey
//
// CREATED: 11/06/1996
//
// COPYRIGHT: Charmed Quark Systems, Ltd @ 2019
//
//  This software is copyrighted by 'Charmed Quark Systems, Ltd' and
//  the author (Dean Roddey.) It is licensed under the MIT Open Source
//  license:
//
//  https://opensource.org/licenses/MIT
//
//  DESCRIPTION:
//
//  This file provides a number of macros that simplify development of new
//  CIDLib classes. They also make it very easy to apply global changes to
//  the way classes are declared.
//
//  Note that these are just the platform independent stuff. Each platform
//  can provide its own core defines via the CIDKernel_PlatformDefines.hpp
//  file in each per-platform directory.
//
// CAVEATS/GOTCHAS:
//
// LOG:
//
//  $_CIDLib_Log_$
//
#pragma once


// ---------------------------------------------------------------------------
//  In order to support some stringizing macros, we have to force a passed
//  macro parameter through a second level of evaluation in order to make sure
//  that the stringizing works against the evaluated replacement value, not
//  the literal macro name.
//
//  The second one is for the common need to L prefix a stringized macro
//  parameter.
//
//  The third is the same, but when the parameter itself is a macro, so we need
//  to get it expanded before we pass it to the 2 version.
// ---------------------------------------------------------------------------
#define CIDLib_ConcatMacro(f,s) f##s
#define CIDLib_Stringize(s) #s
#define CIDLib_MakeLStr(s)  CIDLib_ConcatMacro(L,s)
#define CIDLib_MakeLStr2(sp)  CIDLib_ConcatMacro(L,#sp)
#define CIDLib_MakeLStr3(sp)  CIDLib_MakeLStr2(sp)



// ---------------------------------------------------------------------------
//  This macro generates a standard set of enum manipulation global functions. For
//  those facilities that the IDL compiler doesn't depend on, they will use versions
//  of these generated by the IDL compiler. But the ones that exist below that need
//  to use this macro. This assumes 'enum class' types enums, which all of ours
//  should be.
// ---------------------------------------------------------------------------
#define StdEnumTricks(eEnumType) \
inline eEnumType operator++(eEnumType& eVal, int) \
{ \
    eEnumType eTmp = eVal; \
    eVal = eEnumType(tCIDLib::TCard4(eVal) + 1); \
    return eTmp; \
} \
\
inline eEnumType operator++(eEnumType& eVal) \
{ \
    eVal = eEnumType(tCIDLib::TCard4(eVal) + 1); \
    return eVal; \
} \
\
inline eEnumType operator--(eEnumType& eVal, int) \
{ \
    eEnumType eTmp = eVal; \
    eVal = eEnumType(tCIDLib::TCard4(eVal) - 1); \
    return eTmp; \
} \
\
inline eEnumType operator--(eEnumType& eVal) \
{ \
    eVal = eEnumType(tCIDLib::TCard4(eVal) - 1); \
    return eVal; \
} \
\
inline tCIDLib::TBoolean bIsValidEnum(const eEnumType eVal) \
{ \
    if ((eVal < eEnumType##::Min) || (eVal > eEnumType##::Max)) \
        return kCIDLib::False; \
    return kCIDLib::True; \
}


#define BmpEnumTricks(eEnumType) \
inline eEnumType operator|=(eEnumType& eLHS, const eEnumType eRHS) \
{ \
    eLHS = eEnumType(tCIDLib::TEnumMaskType(eLHS) | tCIDLib::TEnumMaskType(eRHS)); \
    return eLHS; \
} \
\
inline eEnumType operator&=(eEnumType& eLHS, const eEnumType eRHS) \
{ \
    eLHS = eEnumType(tCIDLib::TEnumMaskType(eLHS) & tCIDLib::TEnumMaskType(eRHS)); \
    return eLHS; \
} \
\
inline eEnumType operator|(const eEnumType eLHS, const eEnumType eRHS) \
{ \
    return eEnumType(tCIDLib::TEnumMaskType(eLHS) | tCIDLib::TEnumMaskType(eRHS)); \
} \
\
inline eEnumType operator&(const eEnumType eLHS, const eEnumType eRHS) \
{ \
    return eEnumType(tCIDLib::TEnumMaskType(eLHS) & tCIDLib::TEnumMaskType(eRHS)); \
}




// ---------------------------------------------------------------------------
//  The number of bytes that contain both a1 and a2. a1 should be at the
//  higher address. So it calculates the difference in addresses between the
//  two and then adds in the size of the higher one.
// ---------------------------------------------------------------------------
#define c4BytesIn(a1,a2) \
((((tCIDLib::TCard1*)&a1) - ((tCIDLib::TCard1*)&a2)) + sizeof(a1))


// ---------------------------------------------------------------------------
//  This macro calculates the offset of a field within a structure.
// ---------------------------------------------------------------------------
#define c4FieldOfs(t,f)     (tCIDLib::TCard4(&(((t *)0)->f)))



// ---------------------------------------------------------------------------
//  Calculate the number of chars storable in a buffer. This keeps the
//  calculation from being all over the place. The reason for it is that
//  sizeof(buff) is not valid in a wide char environment. Note that the max
//  chars is 1 less than the full count because it does not include the
//  nul.
// ---------------------------------------------------------------------------
#define c4MaxBufChars(buf)  ((sizeof(buf) / kCIDLib::c4CharBytes) - 1)



// ---------------------------------------------------------------------------
//  This guy generates the little bit of stuff needed to support a null
//  object for a class.
// ---------------------------------------------------------------------------
#define NulObject(typ) \
public : \
  static typ& Nul_##typ(); \
  inline static tCIDLib::TBoolean bIsNullObject(const typ& objToTest) \
  { \
    return (&objToTest == &Nul_##typ()); \
  }



// ---------------------------------------------------------------------------
//  This macro is used to provide the current file name. It handles forcing
//  the __FILE__ macro to be a wide char string.
// ---------------------------------------------------------------------------
#define CID_FILE CIDLib_MakeLStr(__FILE__)


// ---------------------------------------------------------------------------
//  For consistency and flexibility, also alias the line macro
// ---------------------------------------------------------------------------
#define CID_LINE __LINE__


// ---------------------------------------------------------------------------
//  For putting message pragma reminders into code
// ---------------------------------------------------------------------------
#define MakeLINEStr(M, L) M(L)
#define CodeRemLine MakeLINEStr(CIDLib_Stringize, __LINE__)
#define CodeReminder __FILE__ "(" CodeRemLine ") : "
